'''
Author: 吴泳良
Date: 2021-08-09 19:55:22
LastEditTime: 2021-08-17 16:50:40
Description: python函数
'''

# 设置变量为abs函数的别名
a = abs
print(a(-1))

# 什么都不做的函数


def nop():
    pass

# 参数出错的时候会报错，返回多个参数的时候，返回的是元组


def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x


# 给出默认参数，可以只传递一个
def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s


print(power(2))


# 参数数量可变，传入的是一个元组
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum


nums = [1, 2, 3]
print(calc(1, 2, 3))
print(calc(nums[0], nums[1], nums[2]))
# 把list数组的所有元素作为可变参数传递进去
print(calc(*nums))

# 关键字参数，在函数内部自动组装为一个dict
# 如果调用者愿意提供更多的参数，我们也能收到


def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)


person('Michael', 30, city='Beijing')

# 类似于可变参数的调用方法，传入dict
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)

# 限制关键字参数的名字，使用特殊分隔符 *


def person(name, age, *, city, job):
    print(name, age, city, job)


person('gy', 18, city='Harbin', job='student')


# 使用*args和**kw是Python的习惯写法，当然也可以用其他参数名，但最好使用习惯用法。
# 命名关键字参数就是一种特殊的位置参数，它限制了形参名，传递时必须指定形参名。


# 递归函数
def fact(n):
    if n == 1:
        return 1
    return n * fact(n - 1)


print(fact(10))


# 尾递归优化，关键在于num*product这一步，防止栈溢出


def fact(n):
    return fact_iter(n, 1)


def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)
